package com.atguigu.gmall.mapper;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.atguigu.gmall.entiity.Option;
import com.atguigu.gmall.entiity.SaleDetail;
import com.atguigu.gmall.entiity.Stat;
import io.searchbox.client.JestClient;
import io.searchbox.core.Search;
import io.searchbox.core.SearchResult;
import io.searchbox.core.search.aggregation.TermsAggregation;
import org.elasticsearch.index.query.MatchQueryBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.TermsBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import java.io.IOException;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;

/**
 * @ClassName: ESMapper
 * @Description:
 * @Author: kele
 * @Date: 2021/3/28 15:31
 *
 *
 * 1、获取数据
 * 2、解析数据（以字符串的方式返回）
 **/
@Repository
public class ESMapper {


    @Autowired
    private JestClient jestClient;

    /**
     *处理传入的参数，并将查询结果按照SearchResult返回
     *
     *
     * @param date
     * @param startpage
     * @param size
     * @param keyword
     * @return
     * @throws IOException
     */
    public SearchResult getData(String date,Integer startpage,Integer size,String keyword) throws IOException {

        //from和startpage的关系
        Integer fromnum = (startpage-1) * size;

        //按照名称匹配
        MatchQueryBuilder matchQueryBuilder = new MatchQueryBuilder("sku_name", keyword);

        //聚合，查询gender和ageper
        TermsBuilder termsBuilderGender = AggregationBuilders.terms("gender").field("user_gender").size(10);
        TermsBuilder termsBuilderAge = AggregationBuilders.terms("agePer").field("user_age").size(10);

        //SearchSourceBuilder相当于将之前的api通过tostring转化为查询的语句，放到Search中
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder()
                                                .query(matchQueryBuilder)
                                                .aggregation(termsBuilderGender)
                                                .aggregation(termsBuilderAge)
                                                .from(fromnum)
                                                .size(size);


        Search search = new Search.Builder(sourceBuilder.toString())
                .addIndex("gmall2021_sale_detail" + date)
                .addType("_doc")
                .build();

        SearchResult execute = jestClient.execute(search);

        return execute;
    }


    /**
     *  需要將數據解析為 ：
     *      {
     *                 total: xxx,
     *                 stat:
     *                 [
     *                    stat:{
     *                        options:
     *                        [
     *                          {option},
     *                          {option}
     *                        ]
     *                       title: "xxx"
     *                    },
     *                    stat:{
     *                        options:
     *                        [
     *                          {option},
     *                          {option}
     *                        ]
     *                       title: "xxx"
     *                    }
     *
     *                 ]
     *
     *
     *                 detail:
     *                  [
     *                     {saledatail}
     *                 ]
     *
     *             }
     */


    /**
     * 解析传入的数据
     * @param
     */

    //解析detail部分
    public List<SaleDetail> parseDetail(SearchResult data){

        List<SaleDetail> saleDetails = new ArrayList<>();


        //数据转化的类
        List<SearchResult.Hit<SaleDetail, Void>> hits = data.getHits(SaleDetail.class);

        for (SearchResult.Hit<SaleDetail, Void> hit : hits) {

            SaleDetail detail = hit.source;

            //获取es中get的id
            detail.setEs_metadata_id(hit.id);

            saleDetails.add(detail);

        }

        return saleDetails;
    }

    //解析options
    public ArrayList<Stat> parseOptions(SearchResult data){



        //解析男女比例
        TermsAggregation gender = data.getAggregations().getTermsAggregation("gender");

        List<TermsAggregation.Entry> buckets = gender.getBuckets();

        Long maleCount = 0L;
        Long femaleCount = 0L;

        for (TermsAggregation.Entry bucket : buckets) {

            if( bucket.getKey().equals("F") ){
                femaleCount += bucket.getCount();
            }else{
                maleCount += bucket.getCount();
            }
        }

        double sum = femaleCount + maleCount;

        double femalereat =  femaleCount / sum * 100;
        double malereat = maleCount / sum * 100;

        DecimalFormat decimalFormat = new DecimalFormat("##.00");

        String freat = decimalFormat.format(femalereat);
        String mreat = decimalFormat.format(malereat);

        Option foption = new Option("男",Double.parseDouble(freat));
        Option moption = new Option("女",Double.parseDouble(mreat));

        ArrayList<Option> options = new ArrayList<>();
        options.add(foption);
        options.add(moption);

        Stat stateFM = new Stat("男女比例", options);


        //解析各年龄段比例
        TermsAggregation termsAggregation = data.getAggregations().getTermsAggregation("agePer");

        List<TermsAggregation.Entry> bucketsAge = termsAggregation.getBuckets();

        int lt20 = 0;
        int b20and30 = 0;
        int gt30 = 0;

        for (TermsAggregation.Entry entry : bucketsAge) {

            int age = Integer.parseInt(entry.getKey());

            if(age < 20){
                lt20 += entry.getCount();
            }else if(age > 30){
                gt30 += entry.getCount();
            }else{
                b20and30 += entry.getCount();
            }

        }

        double sumNum = lt20 + gt30 + b20and30;

        String lt20Str = decimalFormat.format(lt20 / sumNum * 100);
        String gt30Str = decimalFormat.format(gt30 / sumNum * 100);
        String b20and30Str = decimalFormat.format(b20and30 / sumNum * 100);



        Option option20 = new Option("20岁以下", Double.parseDouble(lt20Str));
        Option option2030 = new Option("30岁及30岁以上", Double.parseDouble(gt30Str));
        Option option30 = new Option("20岁到30岁", Double.parseDouble(b20and30Str));

        ArrayList<Option> optionAge = new ArrayList<>();

        optionAge.add(option20);
        optionAge.add(option2030);
        optionAge.add(option30);

        Stat statAge = new Stat("用户年龄占比",options);

        ArrayList<Stat> stats = new ArrayList<>();

        stats.add(stateFM);
        stats.add(statAge);

        return stats;


    }


    //最终解析结果，以字符串的方式返回
    public JSONObject parseResult(SearchResult data){

        JSONObject jsonObject = new JSONObject();

        jsonObject.put("total",data.getTotal());
        jsonObject.put("detail", parseDetail(data));
        jsonObject.put("stats",parseOptions(data));

        return jsonObject;
    }

}
